El objetivo de este tema es enseñar a diseñar pequeñas interfaces gráficas empleando para ello las librerías gráficas Swing. Una interfaz es lo que le permite a un usuario comunicarse con un programa, una interfaz es lo que nosotros vemos al arrancar, por ejemplo, un navegador de internet: un conjunto de menús, botones, barras.... que nos permiten activar un código que es el que realmente nos llevará a una página web, salvará la imagen en el disco duro....
Las librerías gráficas que usaremos vienen a sustituir a las antiguas AWT. Las nuevas librerías a parte de tener una mayor cantidad de opciones sobre los componentes (como distintas apariencias, control sobre el focus, mayor número de campos que modifican su aspecto, mayor facilidad para pintar al hacer el buffering transparente al usuario....) se diferencian de las anteriores radicalmente en su implementación.
En AWT cuando añadíamos un botón, por ejemplo, a nuestro diseño el compilador generaba código que le pedía al sistema operativo la creación de un botón en un determinado sitio con unas determinadas propiedades; en Swing ya no se pide al sistema operativo nada: se dibuja el botón sobre la ventana en la que lo queríamos. Con esto se eliminaron muchos problemas que existían antes con los códigos de las interfaces gráficas, que debido a depender del sistema operativo para obtener sus componentes gráficos, era necesario testar los programas en distintos sistemas operativos, pudiendo tener distintos bugs en cada uno de ellos. Esto evidentemente iba en contra de la filosofía de Java, supuestamente un lenguaje que no dependía de la plataforma. Con Swing se mejoró bastante este aspecto: lo único que se pide al sistema operativo es una ventana, una vez que tenemos la ventana dibujamos botones, listas, scroll-bars... y todo lo que necesitemos sobre ella.
Evidentemente esta aproximación gana mucho en lo que a independencia de la plataforma se refiere. Además el hecho de que el botón no sea un botón del S.O. sino un botón pintado por Java nos da un mayor control sobre su apariencia.
1.2 JFRAME
Graduación de herencia de JFrame 1
Es el contenedor que emplearemos para situar en él todos los demás componentes que necesitemos para el desarrollo de la interface de nuestro programa. En el gráfico 1 se muestra la jerarquía de herencia de este componente desde Object, que como ya dijimos es el padre de todas las clases de Java. Los métodos de este componente estarán repartidos a lo largo de todos sus ascendientes, cosa que hemos de tener en cuenta cuando consultemos la ayuda on-line de esta clase. Así por ejemplo resulta intuitivo que debiera haber un método para cambiar el color de fondo del frame, pero él no tiene ningún método para ello, lo tiene Component. Veamos el código necesario para crear un Jframe:
Importamos una librería, un package
import javax.swing.*; Nuestra clse frame extiende a JFrame
class frame extends JFrame { el constuctor public frame(){ Este es uno de los métodos que nuestra clase frame ha heredado de JFrame. Pone un título a la ventana setTitle("Hola!!!"); Igual que el anterior, pero le esta vez le da un tamaño setSize(300,200); } }/~
Esta es la clase auxiliar, tiene el main de la aplicación
public class ejemplo13{ public static void main (String[] args){ Creamos un objeto de tipo frame JFrame frame = new frame();
invoco sobre este objeto uno de los métodos que ha heredado de JFrame: show. Los frames por defecto son “invisibles”, este método los hace visibles.
frame.show(); } } ///:~
Si embargo nuestro código anterior tiene un problema: no podemos cerrar la ventana. La única forma de acabar con ella será mediante ^c si hemos ejecutado el programa desde una consola o con Control-Alt-Supr y eliminando su tarea correspondiente si lo ejecutamos desde windows.
¿Por qué no se cierra la ventana? porque no hemos escrito el código necesario para ello. Para que se cierre nuestro frame hemos de escribir un código que escuche los eventos de ventana, y que ante el evento de intentar cerrar la ventana reaccione cerrándose esta. A continuación y antes de seguir con componentes de la librería Swing veamos que es un evento y como gestionarlos.
1.3 Eventos
El sistema de gestión de eventos de Java 1.2 es el mismo que Java 1.1 y por lo tanto el mismo que para las librerías AWT. Aunque los desarrolladores de Java considerasen que para mejorar el lenguaje se necesitaba dejar a un lado las librerías AWT e introducir las Swing no sintieron lo mismo del sistema de gestión de eventos, consideraron que era lo suficientemente bueno.
Realmente este sistema de gestión de eventos es bastante elegante y sencillo, sobre todo si se compara con el sistema de gestión de eventos de Java 1.0, mucho más engorroso de usar y menos elegante.
¿Qué es un evento?
Todos los sistemas operativos están constantemente atendiendo a los eventos generados por los usuarios. Estos eventos pueden ser pulsar una tecla, mover el ratón, hacer clic con el ratón, pulsar el ratón sobre un botón o menú (Java distingue entre simplemente pulsar el ratón en un sitio cualquiera o hacerlo, por ejemplo, en un botón). El sistema operativo notifica a las aplicaciones que están ocurriendo estos eventos, y ellas deciden si han de responder o no de algún modo a este evento.
El modelo de delegación de eventos
El modelo de Java se basa en la delegación de eventos: el evento se produce en un determinado componente, por ejemplo un scroll. Dónde se produce el evento se denomina “fuente del evento”. A continuación el evento se transmite a un ”manejador de eventos” (event listener) que este asignado al componente en el que se produjo el evento. El objeto que escucha los eventos es el que se encargará de responder a ellos adecuadamente. Esta separación de código entre generación del evento y actuación respecto a él facilita la labor del programador y da una mayor claridad a los códigos.
Gestión de eventos en Java.
A la fuente del evento, en este caso un botón, le indicamos quién será su manejador de eventos, manejador que ha de extender la clase Adapter correspondiente o implementar la interfaz Listener (interfaz ActionLitener en este caso). Cuando el usuario genere el evento deseado (en este caso pulse el botón), el objeto fuente empaqueta información a cerca del evento generando un objeto de tipo Event (ActionEvent en este caso) e invoca el método correspondiente del manejador (actionPerformed(actionEvent)) pasándole como información el objeto de tipo Event generado.
Es responsabilidad del manejador, y no de la fuente, responder al evento, por ello se dice que la fuente delega la gestión del evento en el manejador. Lo que la fuente de eventos le pasa al objeto encargado de escuchar los eventos es, como no, otro objeto. Es un objeto tipo Event. En este objeto va toda la información necesaria para la correcta gestión del evento por parte del objeto que escucha los eventos.
El objeto que escucha los eventos ha de implementar para ello una interface. El nombre de esta interface es siempre el nombre del evento más “Listener”: para que un objeto escuche eventos de ratón ha de implementar la interface MouseListener, para que escuche eventos de teclado KeyListener.....
Para hacer que un objeto escuche los eventos de otro objeto se emplea el método add[nombre_evento]Listener, así si tuviésemos un Jframe llamado “frame” y quisiésemos que el objeto llamado “manejador” escuchase los eventos de ratón de “frame” lo haríamos del siguiente modo:
frame.addMouseListener(manejador);
manejador ha de pertenecer a una clase que implemente la interface MouseListener, que tiene un total de 7 métodos que ha de implementar.
A continuación en la siguiente tabla mostramos los eventos más comunes, junto a la interface que debe implementar el objeto que escuche esos eventos y el método para asociar un objeto para escuchar dichos eventos. En la columna de la derecha se presentarán diversos componentes que pueden generar dichos eventos.
Cabe preguntarse ahora por que métodos tiene cada interface, ya que hemos de implementar todos ellos, incluso aunque no los usemos, sino la clase que se encargaría de escuchar los eventos sería abstracta y no podríamos crear ningún objeto de ella. Parece un poco estúpido implementar métodos que no hagan nada sólo porque la interface de la que heredamos los tenga. Así por ejemplo si estamos interesados en escuchar clics de ratón hemos de crear una clase que implemente MouseListener, pero nosotros sólo estaremos interesados en un método de dicha interfase: mouseClicked.
Los creadores de Java también pensaron en esto y por ello para cada interface que tiene más de un método crearon una clase llamada [nombre_evento]Adapter (MouseAdapter), que lo que hace es implementar todos los métodos de la interface sin hacer nada en ellos. Nosotros lo único que tendremos que hacer es que nuestra clase que escuche eventos extienda esta clase y sobrescriba los métodos que nos interesen.
A continuación en la siguiente tabla damos un listado de las principales interfaces junto a sus respectivas clases “Adapter” y los métodos que poseen:
Un frame que se cierra
Pongamos en práctica lo que hemos visto haciendo un frame que se pueda cerrar:
import javax.swing.*; import java.awt.event.*;
class frame extends JFrame { public frame(){ setTitle("Hola!!!"); setSize(300,200);
Le indicamos al frame quien será su manejador de eventos de ventana: un objeto de tipo manejador que creamos en esta misma línea
addWindowListener (new manejador()); } }
/*Clase manejadora de eventos de ventana. Implementa el *inteface WindowListener, por lo que ha de sobreescribir *todos sus métodos*/
class manejador implements WindowListener{
public void windowClosing(WindowEvent e){ System.out.println("sali"); Esta sentencia termina la máquina virtual System.exit(0); }
Métodos que no hacen nada,pero que he de sobreescribir por implementar el interface
public void windowOpened(WindowEvent e){} public void windowClosed(WindowEvent e){} public void windowActivated(WindowEvent e){} public void windowDeactivated(WindowEvent e){} public void windowIconified(WindowEvent e){} public void windowDeiconified(WindowEvent e){} }
public class ejemplo15{ public static void main (String[] args){ JFrame frame = new frame(); frame.show(); } } /:~
Aquí se ve como al hacer que la clase manejador implemente la interface MouseListener hemos de implementar sus siete métodos aunque sólo nos interesa el que está relacionado con el cierre de la ventana. A continuación rescribimos el ejemplo pero aprovechando las ventajas de las clases Adapter:
import javax.swing.*; import java.awt.event.*;
class frame extends JFrame {
public frame(){ setTitle("Hola!!!"); setSize(300,200); Igual que antes le indico a la ventana quién será su manejador de eventos de ventana. addWindowListener (new manejador()); } }
/**Esta vez la clase manejador extiende la clase adapter, por *lo que sólo tengo que sobrescribir el método en el que *estoy interesado*/
class manejador extends WindowAdapter{
public void windowClosing(WindowEvent e){ System.out.println("sali"); System.exit(0); } }
public class ejemplo16{ public static void main (String[] args){ JFrame frame = new frame(); frame.show();
}
} ///:~
1.4 JPANEL
Ahora ya sabemos hacer una ventana (frame) que se cierra. Podríamos empezar a añadirle botones, scrolls, campos de texto ... y todo lo que necesitemos, pero no es considerado una buena práctica de programación añadir componentes directamente sobre un contenedor de “pesado” (frames y applets por lo que a nosotros respecta). Lo correcto es añadir a este uno o varios paneles y añadir sobre los paneles lo que necesitemos.
Una de las ventajas de añadir paneles sobre nuestro frame es que los paneles al derivar de JComponent poseen el método paintComponent que permite dibujar y escribir texto sobre el panel de modo sencillo.
Para añadir un JPanel a nuestro frame primero obtenemos uno de los objetos que forman el frame: el “panel contenedor” (content pane). Para ello invocaremos al método getContentPane de nuestro JFrame. El objeto que nos devuelve será de tipo Container:
A continuación invocamos al método add del Container obtenido para añadir el panel, pasándole el propio panel al método:
[nombre_del_contentpane].add(nombre_del_panel);
Añadámosle un JPanel a nuestro frame: import javax.swing.*; import java.awt.event.*; import java.awt.*; class frame extends JFrame { public frame(){ setTitle("Hola!!!"); setSize(300,200); addWindowListener (new manejador()); Le pido al frame su objeto contenedor Container contentpane = getContentPane();
Creo un objeto de tipo JPanel JPanel panel = new JPanel(); ado el panel en el objeto contenedor del framecontentpane.add(panel); ngo el color de fondo del panel de color rojo panel.setBackground(Color.red);}}
class manejador extends WindowAdapter{public void windowClosing(WindowEvent e){System.out.println("sali");System.exit(0);}} public class ejemplo17{public static void main (String[] args){JFrame frame = new frame();frame.show();}} /:~
1.5 LAYAOUT
Ya ha llegado casi el momento de empezar a añadir cosas a nuestra ventana, sólo una cosa queda pendiente: como controlar dónde añadimos los objetos. Por ejemplo como decirle a nuestro panel dónde tiene que colocar un botón, por ejemplo.
Una solución sería indicarle dónde colocar la esquina izquierda de arriba del botón y luego indicando el alto y ancho del botón. Esto es precisamente lo que hace el método setBounds(int,int,int,int) de la clase Component. Parece, en principio, una buena solución.
class frame extends JFrame { public frame(){ setTitle("Hola!!!"); setSize(500,400); addWindowListener (new manejador()); Container contentpane = getContentPane(); JPanel panel = new JPanel();
imino el gestor de layouts del panel panel.setLayout(null);
Creo un objeto de tipo JButton (un botón) JButton boton = new JButton(); Mediante este método le indico al botón que se sitúe en las coordenadas 300,300 del panel, con un tamaño de 50x50 boton.setBounds(300,300,50,50);
public static void main (String[] args){ JFrame frame = new frame(); frame.show(); } } /:~
Si con este código probamos a cambiar de tamaño la ventana podremos ver como el botón no se mueve, desapareciendo si la ventana se hace muy pequeña y cambiando su posición relativa a los bordes de la ventana. Esto, en una aplicación real, desorientaría al usuario que nunca sabría dónde irlo a buscar al cambiar el tamaño de la ventana.
Para solucionar este inconveniente se crearon los Layout Maneger: con ellos se especifican unas posiciones determinadas en un panel, frame o applet donde añadiremos nuestros componentes o un nuevo panel, al que también le podremos añadir un layout en cuyas posiciones podremos añadir componentes o más panels con layouts....
La posibilidad de añadir varios panels a un layout y fijar a estos nuevos layouts da un gran dinamismo a la hora de colocar los componentes.
FlowLayout
Es el que tienen los paneles por defecto. Los objetos se van colocando en filas en el mismo orden en que se añadieron al contenedor. Cuando se llena una fila se pasa a la siguiente.
Tiene tres posibles constructores:
FlowLayout(); Crea el layout sin añadirle los componentes, con los bordes de unos pegados a otros.
FlowLayout(FlowLayout.LEFT[RIGTH][CENTER]); Indica la alineación de los componentes: a la izquierda, derecha o centro.
Además de la alineación de los componentes indica un espaciado (gap) entre los distintos componentes, de tal modo que no aparecen unos pegados a otros.
He aquí un ejemplo del uso de FlowLayout:
import javax.swing.*; import java.awt.*; class panel extends JFrame{ public panel() { setSize(300,200); Container container = this.getContentPane(); FlowLayout fl = new FlowLayout(FlowLayout.LEFT, 5,10); container.setLayout(fl); for (int i=0; i<4; i++) { JButton button = new JButton("Button"+(i+1)); button.setPreferredSize(new Dimension(100,25)); container.add(button); } } } public class ejemplo19{ public static void main (String[] args){ panel t = new panel(); t.show(); } } /:~
1.6 JButton
Ha llegado el momento de introducir un componente que no sea un mero contenedor. Empecemos por un botón. Crear un botón es tan sencillo como: Button boton = new JButton(); Si queremos que el botón aparezca con una etiqueta de texto:
JButton boton = new JButton(“texto va aquí”);
Veamos como añadirle funcionalidad a nuestro botón. Cada vez que hacemos clic sobre el botón se genera un evento del tipo ActionEvent. Para poder escuchar dichos eventos necesitaremos una clase que implemete la interface ActionListener, interface que tiene un solo método actionPerformed (ActionEvent). Haremos, por ejemplo que al hacer un clic sobre nuestro botón cambie el color de fondo de un panel. Le pondremos un BorderLayout y haremos que el panel sea quien escuche los eventos del botón; para ello ha de implementar la interface ActionListener. Cuando se llame al método actionPerformed invocaremos al método setBackground del panel para cambiarlo a azul. Por otro lado hemos de indicar que va a ser el frame el que escuche los eventos del botón:
boton.addActionListener(this);
El código resultante será:
import java.awt.*;import javax.swing.*;import java.awt.event.*; Ahora la clase frame implementa el interface ActionListener, para poder gestionar eventos de tipo ActionEvent class frame extends JFrame implements ActionListener{ Ahora el panel lo he definido como una variable de la clase no ocal de un método. De este modo podré acceder a ella en cualquier todo de la clase.
JPanel panel = new JPanel(); public frame(){ setTitle("Hola!!!"); setSize(500,400); addWindowListener (new manejador()); Container contentpane = getContentPane();
Le pongo al panel un BorderLayour
panel.setLayout(new BorderLayout()); JButton boton = new JButton("Azul"); Le indico al botón quien será su gestor de eventos de ventana: este propio objeto (this), es decir el frame boton.addActionListener(this); Creo un objeto de tipo dimensión, un objeto que contiene un par de valores enteros Dimension d = new Dimension(); Inicializo ese par de valores enteros d.height = 40; d.width = 100; Le pongo al botón un tamaño preferido, empleando para ello el objeto dimensión que he creado. El BorderLayout respetará el alto preferido del botón al estar éste en su campo sur. boton.setPreferredSize(d); añado el layout al campo sur del panel panel.add(boton,BorderLayout.SOUTH); contentpane.add(panel); panel.setBackground(Color.red); }
La clase frame ha de sobreescribir este método, ya que implementa la interface ActionListener public void actionPerformed (ActionEvent e){ panel.setBackground(Color.blue); } }
class manejador extends WindowAdapter{ public void windowClosing(WindowEvent e){ System.out.println("sali"); System.exit(0); } } Java2, tutorial de javahispano (http://javahispano.org). Página 78 de 119 public class ejemplo22{ public static void main (String[] args){ JFrame frame = new frame(); frame.show(); } } ///:~
1.1 Introducción
El objetivo de este tema es enseñar a diseñar pequeñas interfaces gráficas empleando para ello las librerías gráficas Swing. Una interfaz es lo que le permite a un usuario comunicarse con un programa, una interfaz es lo que nosotros vemos al arrancar, por ejemplo, un navegador de internet: un conjunto de menús, botones, barras.... que nos permiten activar un código que es el que realmente nos llevará a una página web, salvará la imagen en el disco duro....
Las librerías gráficas que usaremos vienen a sustituir a las antiguas AWT. Las nuevas librerías a parte de tener una mayor cantidad de opciones sobre los componentes (como distintas apariencias, control sobre el focus, mayor número de campos que modifican su aspecto, mayor facilidad para pintar al hacer el buffering transparente al usuario....) se diferencian de las anteriores radicalmente en su implementación.
En AWT cuando añadíamos un botón, por ejemplo, a nuestro diseño el compilador generaba código que le pedía al sistema operativo la creación de un botón en un determinado sitio con unas determinadas propiedades; en Swing ya no se pide al sistema operativo nada: se dibuja el botón sobre la ventana en la que lo queríamos. Con esto se eliminaron muchos problemas que existían antes con los códigos de las interfaces gráficas, que debido a depender del sistema operativo para obtener sus componentes gráficos, era necesario testar los programas en distintos sistemas operativos, pudiendo tener distintos bugs en cada uno de ellos. Esto evidentemente iba en contra de la filosofía de Java, supuestamente un lenguaje que no dependía de la plataforma. Con Swing se mejoró bastante este aspecto: lo único que se pide al sistema operativo es una ventana, una vez que tenemos la ventana dibujamos botones, listas, scroll-bars... y todo lo que necesitemos sobre ella.
Evidentemente esta aproximación gana mucho en lo que a independencia de la plataforma se refiere. Además el hecho de que el botón no sea un botón del S.O. sino un botón pintado por Java nos da un mayor control sobre su apariencia.
1.2 JFRAME
Graduación de herencia de JFrame 1
Es el contenedor que emplearemos para situar en él todos los demás componentes que necesitemos para el desarrollo de la interface de nuestro programa. En el gráfico 1 se muestra la jerarquía de herencia de este componente desde Object, que como ya dijimos es el padre de todas las clases de Java. Los métodos de este componente estarán repartidos a lo largo de todos sus ascendientes, cosa que hemos de tener en cuenta cuando consultemos la ayuda on-line de esta clase. Así por ejemplo resulta intuitivo que debiera haber un método para cambiar el color de fondo del frame, pero él no tiene ningún método para ello, lo tiene Component. Veamos el código necesario para crear un Jframe:
Importamos una librería, un package
import javax.swing.*;
Nuestra clse frame extiende a JFrame
class frame extends JFrame {
el constuctor
public frame(){
Este es uno de los métodos que nuestra clase frame ha
heredado de JFrame. Pone un título a la ventana
setTitle("Hola!!!");
Igual que el anterior, pero le esta vez le da un tamaño
setSize(300,200);
}
}/~
Esta es la clase auxiliar, tiene el main de la aplicación
public class ejemplo13{
public static void main (String[] args){
Creamos un objeto de tipo frame
JFrame frame = new frame();
invoco sobre este objeto uno de los métodos que ha heredado
de JFrame: show. Los frames por defecto son “invisibles”,
este método los hace visibles.
frame.show();
}
} ///:~
Si embargo nuestro código anterior tiene un problema: no podemos cerrar la ventana. La única forma de acabar con ella será mediante ^c si hemos ejecutado el programa desde una consola o con Control-Alt-Supr y eliminando su tarea correspondiente si lo ejecutamos desde windows.
¿Por qué no se cierra la ventana? porque no hemos escrito el código necesario para ello. Para que se cierre nuestro frame hemos de escribir un código que escuche los eventos de ventana, y que ante el evento de intentar cerrar la ventana reaccione cerrándose esta. A continuación y
antes de seguir con componentes de la librería Swing veamos que es un evento y como gestionarlos.
1.3 Eventos
El sistema de gestión de eventos de Java 1.2 es el mismo que Java 1.1 y por lo tanto el mismo que para las librerías AWT. Aunque los desarrolladores de Java considerasen que para mejorar el lenguaje se necesitaba dejar a un lado las librerías AWT e introducir las Swing no sintieron lo mismo del sistema de gestión de eventos, consideraron que era lo suficientemente bueno.
Realmente este sistema de gestión de eventos es bastante elegante y sencillo, sobre todo si se compara con el sistema de gestión de eventos de Java 1.0, mucho más engorroso de usar y menos elegante.
¿Qué es un evento?
Todos los sistemas operativos están constantemente atendiendo a los eventos generados por los usuarios. Estos eventos pueden ser pulsar una tecla, mover el ratón, hacer clic con el ratón, pulsar el ratón sobre un botón o menú (Java distingue entre simplemente pulsar el ratón en un sitio cualquiera o hacerlo, por ejemplo, en un botón). El sistema operativo notifica a las aplicaciones que están ocurriendo estos eventos, y ellas deciden si han de responder o no de algún modo a este evento.
El modelo de delegación de eventos
El modelo de Java se basa en la delegación de eventos: el evento se produce en un determinado componente, por ejemplo un scroll. Dónde se produce el evento se denomina “fuente del evento”. A continuación el evento se transmite a un ”manejador de eventos” (event listener) que este asignado al componente en el que se produjo el evento. El objeto que escucha los eventos es el que se encargará de responder a ellos adecuadamente. Esta separación de código entre generación del evento y actuación respecto a él facilita la labor del programador y da una mayor claridad a los códigos.
Gestión de eventos en Java.
A la fuente del evento, en este caso un botón, le indicamos quién será su manejador de eventos, manejador que ha de extender la clase Adapter correspondiente o implementar la interfaz Listener (interfaz ActionLitener en este caso). Cuando el usuario genere el evento deseado (en este caso pulse el botón), el objeto fuente empaqueta información a cerca del evento generando un objeto de tipo Event (ActionEvent en este caso) e invoca el método correspondiente del manejador (actionPerformed(actionEvent)) pasándole como información el objeto de tipo Event generado.
Es responsabilidad del manejador, y no de la fuente, responder al evento, por ello se dice que la fuente delega la gestión del evento en el manejador. Lo que la fuente de eventos le pasa al objeto encargado de escuchar los eventos es, como no, otro objeto. Es un objeto tipo Event. En este objeto va toda la información necesaria para la correcta gestión del evento por parte del objeto que escucha los eventos.
El objeto que escucha los eventos ha de implementar para ello una interface. El nombre de esta interface es siempre el nombre del evento más “Listener”: para que un objeto escuche eventos de ratón ha de implementar la interface MouseListener, para que escuche eventos de teclado KeyListener.....
Para hacer que un objeto escuche los eventos de otro objeto se emplea el método add[nombre_evento]Listener, así si tuviésemos un Jframe llamado “frame” y quisiésemos que el objeto llamado “manejador” escuchase los eventos de ratón de “frame” lo haríamos del siguiente modo:
frame.addMouseListener(manejador);
manejador ha de pertenecer a una clase que implemente la interface MouseListener, que tiene un total de 7 métodos que ha de implementar.
A continuación en la siguiente tabla mostramos los eventos más comunes, junto a la interface que debe implementar el objeto que escuche esos eventos y el método para asociar un objeto para escuchar dichos eventos. En la columna de la derecha se presentarán diversos componentes que pueden generar dichos eventos.
Cabe preguntarse ahora por que métodos tiene cada interface, ya que hemos de implementar todos ellos, incluso aunque no los usemos, sino la clase que se encargaría de escuchar los eventos sería abstracta y no podríamos crear ningún objeto de ella. Parece un poco estúpido
implementar métodos que no hagan nada sólo porque la interface de la que heredamos los tenga. Así por ejemplo si estamos interesados en escuchar clics de ratón hemos de crear una clase que implemente MouseListener, pero nosotros sólo estaremos interesados en un método de dicha interfase: mouseClicked.
Los creadores de Java también pensaron en esto y por ello para cada interface que tiene más de un método crearon una clase llamada [nombre_evento]Adapter (MouseAdapter), que lo que hace es implementar todos los métodos de la interface sin hacer nada en ellos. Nosotros lo único que tendremos que hacer es que nuestra clase que escuche eventos extienda esta clase y sobrescriba los métodos que nos interesen.
A continuación en la siguiente tabla damos un listado de las principales interfaces junto a sus respectivas clases “Adapter” y los métodos que poseen:
Un frame que se cierra
Pongamos en práctica lo que hemos visto haciendo un frame que se pueda cerrar:
import javax.swing.*;
import java.awt.event.*;
class frame extends JFrame {
public frame(){
setTitle("Hola!!!");
setSize(300,200);
Le indicamos al frame quien será su manejador de eventos de
ventana: un objeto de tipo manejador que creamos en esta misma línea
addWindowListener (new manejador());
}
}
/*Clase manejadora de eventos de ventana. Implementa el
*inteface WindowListener, por lo que ha de sobreescribir
*todos sus métodos*/
class manejador implements WindowListener{
public void windowClosing(WindowEvent e){
System.out.println("sali");
Esta sentencia termina la máquina virtual
System.exit(0);
}
Métodos que no hacen nada,pero que he de sobreescribir por
implementar el interface
public void windowOpened(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
}
public class ejemplo15{
public static void main (String[] args){
JFrame frame = new frame();
frame.show();
}
}
/:~
Aquí se ve como al hacer que la clase manejador implemente la interface MouseListener hemos de implementar sus siete métodos aunque sólo nos interesa el que está relacionado con el cierre de la ventana. A continuación rescribimos el ejemplo pero aprovechando las ventajas de las clases Adapter:
import javax.swing.*;
import java.awt.event.*;
class frame extends JFrame {
public frame(){
setTitle("Hola!!!");
setSize(300,200);
Igual que antes le indico a la ventana quién será su
manejador de eventos de ventana.
addWindowListener (new manejador());
}
}
/**Esta vez la clase manejador extiende la clase adapter, por
*lo que sólo tengo que sobrescribir el método en el que
*estoy interesado*/
class manejador extends WindowAdapter{
public void windowClosing(WindowEvent e){
System.out.println("sali");
System.exit(0);
}
}
public class ejemplo16{
public static void main (String[] args){
JFrame frame = new frame();
frame.show();
}
} ///:~
1.4 JPANEL
Ahora ya sabemos hacer una ventana (frame) que se cierra. Podríamos empezar a añadirle
botones, scrolls, campos de texto ... y todo lo que necesitemos, pero no es considerado una buena práctica de programación añadir componentes directamente sobre un contenedor de “pesado” (frames y applets por lo que a nosotros respecta). Lo correcto es añadir a este uno o varios paneles y añadir sobre los paneles lo que necesitemos.
Una de las ventajas de añadir paneles sobre nuestro frame es que los paneles al derivar de
JComponent poseen el método paintComponent que permite dibujar y escribir texto sobre el
panel de modo sencillo.
Para añadir un JPanel a nuestro frame primero obtenemos uno de los objetos que forman el
frame: el “panel contenedor” (content pane). Para ello invocaremos al método getContentPane de nuestro JFrame. El objeto que nos devuelve será de tipo Container:
Container [nombre_del_contentpane] = frame.getContentPane();
A continuación invocamos al método add del Container obtenido para añadir el panel, pasándole el propio panel al método:
[nombre_del_contentpane].add(nombre_del_panel);
Añadámosle un JPanel a nuestro frame:
import javax.swing.*; import java.awt.event.*; import java.awt.*;
class frame extends JFrame {
public frame(){ setTitle("Hola!!!"); setSize(300,200); addWindowListener (new manejador()); Le pido al frame su objeto contenedor Container contentpane = getContentPane();
Creo un objeto de tipo JPanel
JPanel panel = new JPanel();
ado el panel en el objeto contenedor del framecontentpane.add(panel);
ngo el color de fondo del panel de color rojo
panel.setBackground(Color.red);}}
class manejador extends WindowAdapter{public void windowClosing(WindowEvent e){System.out.println("sali");System.exit(0);}}
public class ejemplo17{public static void main (String[] args){JFrame frame = new frame();frame.show();}} /:~
1.5 LAYAOUT
Ya ha llegado casi el momento de empezar a añadir cosas a nuestra ventana, sólo una cosa queda pendiente: como controlar dónde añadimos los objetos. Por ejemplo como decirle a nuestro panel dónde tiene que colocar un botón, por ejemplo.Una solución sería indicarle dónde colocar la esquina izquierda de arriba del botón y luego indicando el alto y ancho del botón. Esto es precisamente lo que hace el método setBounds(int,int,int,int) de la clase Component. Parece, en principio, una buena solución.
Hagámoslo:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
class frame extends JFrame {
public frame(){
setTitle("Hola!!!");
setSize(500,400);
addWindowListener (new manejador());
Container contentpane = getContentPane();
JPanel panel = new JPanel();
imino el gestor de layouts del panel
panel.setLayout(null);
Creo un objeto de tipo JButton (un botón)
JButton boton = new JButton();
Mediante este método le indico al botón que se sitúe en las coordenadas 300,300 del panel, con un tamaño de 50x50
boton.setBounds(300,300,50,50);
Añado el botón al panel
panel.add(boton);
contentpane.add(panel);
panel.setBackground(Color.red);
}
}
public static void main (String[] args){ JFrame frame = new frame(); frame.show(); } } /:~
Si con este código probamos a cambiar de tamaño la ventana podremos ver como el botón no se mueve, desapareciendo si la ventana se hace muy pequeña y cambiando su posición relativa a los bordes de la ventana. Esto, en una aplicación real, desorientaría al usuario que nunca sabría dónde irlo a buscar al cambiar el tamaño de la ventana.
Para solucionar este inconveniente se crearon los Layout Maneger: con ellos se especifican unas posiciones determinadas en un panel, frame o applet donde añadiremos nuestros componentes o un nuevo panel, al que también le podremos añadir un layout en cuyas posiciones podremos añadir componentes o más panels con layouts....
La posibilidad de añadir varios panels a un layout y fijar a estos nuevos layouts da un gran dinamismo a la hora de colocar los componentes.
FlowLayout
Es el que tienen los paneles por defecto. Los objetos se van colocando en filas en el mismo orden en que se añadieron al contenedor. Cuando se llena una fila se pasa a la siguiente.
Tiene tres posibles constructores:
FlowLayout();
Crea el layout sin añadirle los componentes, con los bordes de unos pegados a otros.
FlowLayout(FlowLayout.LEFT[RIGTH][CENTER]);
Indica la alineación de los componentes: a la izquierda, derecha o centro.
FlowLayout(FlowLayout.LEFT, gap_horizontal, gap_vertical);
Además de la alineación de los componentes indica un espaciado (gap) entre los distintos componentes, de tal modo que no aparecen unos pegados a otros.
He aquí un ejemplo del uso de FlowLayout:
import javax.swing.*; import java.awt.*;
class panel extends JFrame{
public panel() {
setSize(300,200);
Container container = this.getContentPane();
FlowLayout fl = new FlowLayout(FlowLayout.LEFT, 5,10);
container.setLayout(fl);
for (int i=0; i<4; i++) {
JButton button = new JButton("Button"+(i+1));
button.setPreferredSize(new Dimension(100,25));
container.add(button);
}
}
}
public class ejemplo19{
public static void main (String[] args){
panel t = new panel();
t.show();
}
}
/:~
1.6 JButton
Ha llegado el momento de introducir un componente que no sea un mero contenedor. Empecemos por un botón. Crear un botón es tan sencillo como:
Button boton = new JButton();
Si queremos que el botón aparezca con una etiqueta de texto:
JButton boton = new JButton(“texto va aquí”);
Veamos como añadirle funcionalidad a nuestro botón. Cada vez que hacemos clic sobre el botón se genera un evento del tipo ActionEvent. Para poder escuchar dichos eventos necesitaremos una clase que implemete la interface ActionListener, interface que tiene un solo
método actionPerformed (ActionEvent). Haremos, por ejemplo que al hacer un clic sobre nuestro botón cambie el color de fondo de un
panel. Le pondremos un BorderLayout y haremos que el panel sea quien escuche los eventos del botón; para ello ha de implementar la interface ActionListener. Cuando se llame al método actionPerformed invocaremos al método setBackground del panel para cambiarlo a azul. Por otro lado hemos de indicar que va a ser el frame el que escuche los eventos del botón:
boton.addActionListener(this);
El código resultante será:
import java.awt.*;import javax.swing.*;import java.awt.event.*;
Ahora la clase frame implementa el interface
ActionListener, para poder gestionar eventos de tipo ActionEvent
class frame extends JFrame implements ActionListener{
Ahora el panel lo he definido como una variable de la clase no ocal de un método. De este modo podré acceder a ella en cualquier
todo de la clase.
JPanel panel = new JPanel();
public frame(){
setTitle("Hola!!!");
setSize(500,400);
addWindowListener (new manejador());
Container contentpane = getContentPane();
Le pongo al panel un BorderLayour
panel.setLayout(new BorderLayout());
JButton boton = new JButton("Azul");
Le indico al botón quien será su gestor de eventos de
ventana: este propio objeto (this), es decir el frame
boton.addActionListener(this);
Creo un objeto de tipo dimensión, un objeto que contiene un
par de valores enteros
Dimension d = new Dimension();
Inicializo ese par de valores enteros
d.height = 40;
d.width = 100;
Le pongo al botón un tamaño preferido, empleando para ello
el objeto dimensión que he creado. El BorderLayout
respetará el alto preferido del botón al estar éste en su
campo sur.
boton.setPreferredSize(d);
añado el layout al campo sur del panel
panel.add(boton,BorderLayout.SOUTH);
contentpane.add(panel);
panel.setBackground(Color.red);
}
La clase frame ha de sobreescribir este método, ya que implementa la interface ActionListener
public void actionPerformed (ActionEvent e){
panel.setBackground(Color.blue);
}
}
class manejador extends WindowAdapter{
public void windowClosing(WindowEvent e){
System.out.println("sali");
System.exit(0);
}
}
Java2, tutorial de javahispano (http://javahispano.org). Página 78 de 119
public class ejemplo22{
public static void main (String[] args){
JFrame frame = new frame();
frame.show();
}
} ///:~